﻿using Core.DataAccess.Model;
using Core.DataAccess.Model.iTool.Gateway;
using Core.Framework;
using Environment.Interfaces;
using HandlerContextOptions;
using Microsoft.EntityFrameworkCore;
using Ocelot.Configuration.Creator;
using Ocelot.Configuration.Repository;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Environment.Implements
{
    public class ApiGateway : IApiGateway
    {

        IFileConfigurationRepository configurationRepo;
        IInternalConfigurationCreator internalConfigurationCreator;
        IInternalConfigurationRepository internalConfigurationRepo;
        public ApiGateway(
            IFileConfigurationRepository fileConfigurationRepository,
            IInternalConfigurationCreator iInternalConfigurationCreator,
            IInternalConfigurationRepository internalConfigurationRepository)
        {
            this.configurationRepo = fileConfigurationRepository;
            this.internalConfigurationRepo = internalConfigurationRepository;
            this.internalConfigurationCreator = iInternalConfigurationCreator;
        }

        public async Task<bool> AddOrUpdateGlobalConfig(GatewayGlobalOption options)
        {
            try
            {
                await using (iToolGatewayContext context = new iToolGatewayContext())
                {
                    var config = await context.GatewayRoutes.Where(item => item.RouteType == 0).FirstOrDefaultAsync();

                    if (config == null)
                    {
                        await context.GatewayRoutes.AddAsync(new GatewayRoute
                        {
                            RouteConfig = options.TryToJson(),
                            RouteType = 0,
                            RouteCreateTime = DateTime.Now
                        });
                    }
                    else
                    {
                        config.RouteConfig = options.TryToJson();
                    }

                    await context.SaveChangesAsync();
                    await this.ModifyConfiguration();
                    return true;
                }

            }
            catch
            {
                return false;
            }
        }

        public async Task<GatewayRoute> AddRoute(GatewayRoutesOptions options)
        {
            var route = new GatewayRoute
            {
                RouteConfig = options.TryToJson(),
                RouteType = 1,
                RouteCreateTime = DateTime.Now
            };

            await using (iToolGatewayContext context = new iToolGatewayContext())
            {
                try
                {
                    await context.GatewayRoutes.AddAsync(route);
                    await context.SaveChangesAsync();
                    await ModifyConfiguration();
                    return route;
                }
                catch (Exception ex)
                {
                    context.GatewayRoutes.Remove(route);
                    await context.SaveChangesAsync();

                    return new GatewayRoute
                    {
                        RouteConfig = ex.Message
                    };
                }
            }
        }

        public async Task<GatewayRoute> EditRoute(int id, GatewayRoutesOptions options)
        {
            string oldConfig = string.Empty;
            await using (iToolGatewayContext context = new iToolGatewayContext())
            {
                var config = await context.GatewayRoutes.FindAsync(id);
                try
                {
                    if (config == null)
                    {
                        return new GatewayRoute
                        {
                            RouteConfig = "更新的路由不存在"
                        };
                    }
                    else
                    {
                        oldConfig = config.RouteConfig;
                        config.RouteConfig = options.TryToJson();
                        config.RouteCreateTime = DateTime.Now;
                    }
                    await context.SaveChangesAsync();
                    await this.ModifyConfiguration();

                    return config;
                }
                catch (Exception ex)
                {
                    config.RouteConfig = oldConfig;
                    config.RouteCreateTime = DateTime.Now;
                    await context.SaveChangesAsync();

                    return new GatewayRoute
                    {
                        RouteConfig = ex.Message
                    };
                }
            }

        }

        public async Task<GatewayRoute> GetGlobalConfig()
        {
            await using (iToolGatewayContext context = new iToolGatewayContext())
            {
                try
                {
                    return await context.GatewayRoutes.Where(item => item.RouteType == 0).FirstOrDefaultAsync();
                }
                catch
                {
                    return null;
                }
            }

        }

        public async Task<List<GatewayRoute>> GetRoutes(Pagination pagination)
        {
            await using (iToolGatewayContext context = new iToolGatewayContext())
            {
                return await context
                           .GatewayRoutes
                           .Where(item => item.RouteType == 1)
                           .PaginationAsync(pagination);
            }

        }

        public async Task<bool> RemoveRoute(int id)
        {
            await using (iToolGatewayContext context = new iToolGatewayContext())
            {
                try
                {
                    var config = await context.GatewayRoutes.FindAsync(id);

                    if (config == null)
                    {
                        return false;
                    }
                    else
                    {
                        context.GatewayRoutes.Remove(config);
                    }

                    await context.SaveChangesAsync();
                    await this.ModifyConfiguration();
                    return true;
                }
                catch
                {
                    return false;
                }
            }

        }



        private async Task ModifyConfiguration(int reTryCount = 0)
        {
            var ocelotConfiguration = await configurationRepo.Get();
            if (!ocelotConfiguration.IsError)
            {
                var internalConfiguration =
                    await internalConfigurationCreator.Create(ocelotConfiguration.Data);
                if (!internalConfiguration.IsError)
                {
                    internalConfigurationRepo.AddOrReplace(internalConfiguration.Data);
                }
                else
                {

                    //if (reTryCount < 5)
                    //{
                    //    reTryCount++;
                    //    await Task.Delay(reTryCount * 1000);
                    //    await ModifyConfiguration(reTryCount);
                    //}

                    throw new Exception($"init api route configuration error,{string.Join(", ", internalConfiguration.Errors)}");
                }
            }
            else
            {

                //reTryCount++;
                //await Task.Delay(reTryCount * 1000);
                //await ModifyConfiguration(reTryCount);

                throw new Exception($"init api route configuration error, {string.Join(", ", ocelotConfiguration.Errors)}");
            }
        }
    }
}
